package com.leyou.search.service.impl;

import com.leyou.common.Exception.LyException;
import com.leyou.common.dto.PageDTO;
import com.leyou.item.client.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.item.dto.SpecParamDTO;
import com.leyou.item.dto.SpuDTO;
import com.leyou.search.entity.Goods;
import com.leyou.search.entity.SearchParamDTO;
import com.leyou.search.repository.GoodsRepository;
import com.leyou.search.service.SearchService;
import com.leyou.starter.elastic.dto.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import reactor.core.publisher.Mono;
//静态导入
import java.util.*;
import java.util.stream.Collectors;

import static com.leyou.search.constans.SearchConstants.*;

@Slf4j
@Service
public class SearchServiceImpl implements SearchService {


    @Autowired
    GoodsRepository repository;

    @Autowired
    ItemClient itemClient;
    @Override
    public void createIndexAndMapping() {
        //尝试删除索引库
        try {
            log.warn("尝试删除存在的索引库");
            repository.deleteIndex();
        } catch (Exception e) {
           log.warn("索引库不存在,无需删除");
        }
        //创建索引库和映射
        log.warn("尝试重新创建索引库");
        repository.createIndex(SOURCE_TEMPLATE);
    }

    @Override
    public void loadData() {
        int page=1;
        int rows=10;
        while (true) {
            //1.查询商品
            PageDTO<SpuDTO> info = itemClient.querySpuByPage(page, rows, true, null, null, null);
            List<SpuDTO> spuList = info.getItems();
            //2.把spu数据封装到goods
            List<Goods> goodsList = spuList.stream().map(this::buildGoods).collect(Collectors.toList());
     /*   List<Goods> goodsList=new ArrayList<>();
        for (SpuDTO spuDTO : spuList) {
          Goods goods=buildGoods(spuDTO);
          goodsList.add(goods);
        }*/

            //3.写入elasticsearch
            repository.saveAll(goodsList);
            if (page>=info.getTotalPage()){
                //已经查到最后一页
                break;
            }
            //4.翻页
            page++;
        }
        log.info("全部数据导入成功,共{}页",page);
    }

    @Override
    public Mono<List<String>> getSuggestion(String keyPrefix) {
        return  repository.suggestBySingleField( SUGGEST_FIELD,keyPrefix);
    }

    @Override
    public Mono<PageInfo<Goods>> searchGoodsList(SearchParamDTO paramDTO) {
        //构建搜索条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //1.source过滤
        sourceBuilder.fetchSource(INCLUDE_SOURCE,EMPTY_SOURCE);
        //2.query查询
        String key = paramDTO.getKey();
        if (StringUtils.isBlank(key)){
            throw new LyException("没有找到与“”相关的商品",404);
        }
        sourceBuilder.query(QueryBuilders.boolQuery()
                .must(QueryBuilders.matchQuery(SEARCH_FIELD,key)));
        //3.sort排序
        String sortBy = paramDTO.getSortBy();
        if (StringUtils.isNotBlank(sortBy)){
            //需要排序
            sourceBuilder.sort(sortBy,paramDTO.getDesc()? SortOrder.DESC : SortOrder.ASC);
        }
        //4.分页
        sourceBuilder.from(paramDTO.getFrom()).size(paramDTO.getSize());
        //5.高亮
        sourceBuilder.highlighter(new HighlightBuilder().field(HIGHLIGHT_FIELD).preTags(PRE_TAG).postTags(POST_TAG));

        return repository.queryBySourceBuilderForPageHighlight(sourceBuilder);
    }

    @Override
    public void saveItemBySpuId(Long spuId) {
        //查询spu
        SpuDTO spu = itemClient.queryGoodsById(spuId);
        //构建Goods
        Goods goods = buildGoods(spu);
        //新增goods
        repository.save(goods);
    }

    @Override
    public void deleteItemBySpuId(Long spuId) {
        repository.deleteById(spuId);
    }

    private Goods buildGoods(SpuDTO spuDTO) {
        //1.商品标题,原有标签基础上,拼接分类名称,品牌名称
        String title=spuDTO.getTitle()+spuDTO.getBrandName()+spuDTO.getCategoryName();
        //2.suggestion: 自动补全字段,包含：商品名称.分类名称.品牌名称
        Set<String> suggestion=new HashSet<>();
        suggestion.add(spuDTO.getName());
        suggestion.add(spuDTO.getBrandName());
        Collections.addAll(suggestion,spuDTO.getCategoryName().split("/"));
        //3.规格参数specs, List<Map<String,Object>>  key是name和value,name的值是规格参数名称 ,value的值是规格参数的值
        //3.1先查询出规格参数的name和value
        List<SpecParamDTO> params = itemClient.querySpecsValues(spuDTO.getId(), true);
        //3.2 准备specs集合
        List<Map<String,Object>> specs=new ArrayList<>(params.size());
        //3.3 把SpecParamDTO 变为一个Map<String,Object>
        for (SpecParamDTO param : params) {
            Map<String,Object> map=new HashMap<>(2);
            map.put("name",param.getName());
            map.put("value",chooseSegment(param));
            specs.add(map);
        }
        //4.sku相关信息 包括：图片,价格,销量
        List<SkuDTO> skuList = spuDTO.getSkus();
        //4.0 健壮性判断
        if (CollectionUtils.isEmpty(skuList)){
            //skuList为空
             skuList = itemClient.querySkuBySpuId(spuDTO.getId());
        }
        //4.1销量
        Long sold=0L;
        //4.2 价格
       Set<Long> prices=new TreeSet<>();

        for (SkuDTO skuDTO : skuList) {
            sold+=skuDTO.getSold();
            prices.add(skuDTO.getPrice());
        }
        //4.3 图片,取一张即可
      /*  String images = skuList.get(0).getImages();
        String image = StringUtils.substringBefore(images, ",");*/
        String image= StringUtils.substringBefore(skuList.get(0).getImages(), ",");
        //5.封装goods
        Goods goods = new Goods();
        goods.setUpdateTime(new Date());
        goods.setTitle(spuDTO.getTitle());
        goods.setSuggestion(suggestion);
        goods.setSpecs(specs);
        goods.setSold(sold);
        goods.setPrices(prices);
        goods.setImage(image);
        goods.setId(spuDTO.getId());
        goods.setCategoryId(spuDTO.getCid3());
        goods.setBrandId(spuDTO.getBrandId());
        return goods;
    }
    private Object chooseSegment(SpecParamDTO p) {
        Object value = p.getValue();
        if (value == null || StringUtils.isBlank(value.toString())) {
            return "其它";
        }
        if(!p.getNumeric() || StringUtils.isBlank(p.getSegments()) || value instanceof Collection){
            return value;
        }
        double val = parseDouble(value.toString());
        String result = "其它";
        // 保存数值段
        for (String segment : p.getSegments().split(",")) {
            String[] segs = segment.split("-");
            // 获取数值范围
            double begin = parseDouble(segs[0]);
            double end = Double.MAX_VALUE;
            if (segs.length == 2) {
                end = parseDouble(segs[1]);
            }
            // 判断是否在范围内
            if (val >= begin && val < end) {
                if (segs.length == 1) {
                    result = segs[0] + p.getUnit() + "以上";
                } else if (begin == 0) {
                    result = segs[1] + p.getUnit() + "以下";
                } else {
                    result = segment + p.getUnit();
                }
                break;
            }
        }
        return result;
    }

    private double parseDouble(String str) {
        try {
            return Double.parseDouble(str);
        } catch (Exception e) {
            return 0;
        }
    }
}
